/*
 * Base_Pool.h
 *
 *  Created on: 2014. 6. 23.
 *      Author: jjaehuny
 */

#ifndef FRAMEWORK_MEMORY_BASE_POOL_H_
#define FRAMEWORK_MEMORY_BASE_POOL_H_

#include <memory>
#include <deque>

namespace Framework { namespace Memory {

template<class Type>
class Base_Pool
{
public:
	Base_Pool (bool bPost = false, unsigned long pool_size = 1);
	virtual ~Base_Pool ();

	Base_Pool (const Base_Pool & other) = delete;
	Base_Pool & operator= (const Base_Pool & other) = delete;

public:
	virtual std::shared_ptr<Type> NEW ();
	void Post (Type * pType);

protected:
	virtual Type * allocator ();
	virtual void deleter (Type * pType);

protected:
	std::deque<Type *> type_deque_;
};

template<class Type>
Base_Pool<Type>::Base_Pool (bool bPost, unsigned long pool_size)
{
	type_deque_.clear();

	if (true == bPost)
	{
		for (unsigned long ulCount = 0; ulCount < pool_size; ulCount++)
			this->Post(new Type);
	}
}

template<class Type>
Base_Pool<Type>::~Base_Pool ()
{
	for (auto * pType : type_deque_)
		delete pType;

	type_deque_.clear();
}

template<class Type> std::shared_ptr<Type>
Base_Pool<Type>::NEW ()
{
	Type * pType = this->allocator();

	return std::shared_ptr<Type>(pType, [this](Type * pType) {
		if (NULL != pType)
		{
			this->deleter(pType);
		}
	} );
}

template<class Type> void
Base_Pool<Type>::Post (Type * pType)
{
	if (NULL != pType)
		type_deque_.push_back(pType);
}

template<class Type> Type *
Base_Pool<Type>::allocator ()
{
	Type * pType = NULL;
	{
		if (true != type_deque_.empty())
		{
			pType = type_deque_.front();
			type_deque_.pop_front();
		}
	}

	return pType;
}

template<class Type> void
Base_Pool<Type>::deleter (Type * pType)
{
	if (NULL != pType)
		type_deque_.push_back(pType);
}

} /*Memory*/ } /*Framework*/

#endif /* FRAMEWORK_MEMORY_BASE_POOL_H_ */
